﻿namespace Modbus.Net8.Commom
{
    public class Crc16
    {
        // CRC-16-CCITT polynomial: x^16 + x^12 + x^5 + 1 (0x1021)
        private const ushort polynomial = 0xA001;
        private static ushort[] table;

        /// <summary>
        /// 初始化查找表
        /// </summary>
        static void Init()
        {
            // 初始化查找表
            table = new ushort[256];
            for (ushort i = 0; i < table.Length; ++i)
            {
                ushort value = i;
                for (byte j = 0; j < 8; ++j)
                {
                    if ((value & 1) != 0)
                    {
                        value = (ushort)((value >> 1) ^ polynomial);
                    }
                    else
                    {
                        value >>= 1;
                    }
                }
                table[i] = value;
            }
        }

        /// <summary>
        /// 生成CRC
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static ushort ComputeCheckSum(byte[] bytes)
        {
            ushort crc = 0xFFFF;
            if (table == null)
                Init();

            foreach (byte b in bytes)
            {
                byte lowByte = (byte)(crc & 0xFF);
                crc >>= 8;
                crc ^= table[lowByte ^ b];
            }

            return crc;
        }

        /// <summary>
        /// 校验CRC
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="len"></param>
        /// <param name="idx"></param>
        /// <returns></returns>
        public static ushort ComputeCheckSum(byte[] bytes, int len, int idx = 0)
        {
            ushort crc = 0xFFFF;
            if (idx >= 0 && len <= bytes.Length && len > idx)
            {
                if (table == null)
                    Init();

                for (int i = idx; len > i; i++)
                {
                    byte lowByte = (byte)(crc & 0xFF);
                    crc >>= 8;
                    crc ^= table[lowByte ^ bytes[i]];
                }
            }

            return crc;
        }
    }
}
